<?php

namespace App\Service\WeChat;


use App\Service\Dir;


class MiniPayV2
{

    // 小程序支付
    //   独立，不依赖于其他程序


    // 参数
    protected $mini_appid; // 微信小程序 AppID
    protected $mini_key;   // 微信小程序 key
    protected $mchid;      // 微信支付商户号


    // 初始化
    public function __construct($appId, $key, $mchid)
    {
        $this->mini_appid = $appId;
        $this->mini_key   = $key;
        $this->mchid      = $mchid;
    }

    // 生成支付
    public function wxMiniPay($orderNo, $openid, $money, $body, $notify_url)
    {
        $paramarr = $this->payParam($orderNo, $openid, $money, $body, $notify_url);
        /*var_dump($paramarr);
        die;*/


        $paramXml = $this->makeXml($paramarr);
        /*var_dump($paramXml);
        die;*/

        // 请求腾讯服务器 获取支付前的信息
        $resultXml = $this->curlXml($paramXml);
        $result2   = $this->xmlToArray($resultXml);
        if($result2['return_code'] == 'FAIL'){
            return $this->_returnFail($result2['return_msg']);
        }

        // 组合给前端调取支付
        $time2     = time();
        $prepayid  = $result2['prepay_id'];
        $paramarr2 = $this->toJsPay($this->mini_appid, $time2, $prepayid, $this->mini_key);

        return $paramarr2;
    }

    // 请求之前的参数
    protected function payParam($orderNo, $openid, $money, $body, $notify_url)
    {
        $noceStr  = $this->noceStr(time());
        $paramarr = array(
            "appid"            => $this->mini_appid,   // 参数：1
            "body"             => $body,   // 参数：2
            "mch_id"           => $this->mchid,   // 参数：3
            "nonce_str"        => $noceStr,
            "notify_url"       => $notify_url,  // 异步回调
            "openid"           => $openid,     // 参数：4
            "out_trade_no"     => $orderNo,    // 参数：5
            "spbill_create_ip" => $_SERVER["REMOTE_ADDR"],
            "total_fee"        => $money * 100,
            "trade_type"       => "JSAPI",
        );

        // 签名
        $paramarr['sign'] = $this->sign($paramarr, $this->mini_key);//生成签名


        return $paramarr;
    }


    // 请求 传递xml
    protected function curlXml($paramXml)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, true);  // 从证书中检查SSL加密算法是否存在
        curl_setopt($ch, CURLOPT_URL, "https://api.mch.weixin.qq.com/pay/unifiedorder");
        curl_setopt($ch, CURLOPT_URL, "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $paramXml);

        // 获取返回结果
        //  如果报错，则报错错误信息
        $resultXml = curl_exec($ch);
        if(curl_errno($ch)){
            $this->logCurl(curl_error($ch));
        }

        curl_close($ch);

        return $resultXml;
    }


    /**
     * xml转为数组
     */
    protected function xmlToArray($xmlStr)
    {
        $postStr = $xmlStr;
        $msg     = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);

        return $msg;
    }

    // 制作 xml
    protected function makeXml($arr)
    {
        $xml = "<xml>";
        foreach($arr as $k => $v){
            $xml .= "<".$k.">".$v."</".$k.">";
        }
        $xml .= "</xml>";

        return $xml;
    }

    // 组合给前端调取支付： 注意参数大小写
    protected function toJsPay($appId, $timeStamp, $prepayid, $wx_mini_key)
    {
        $noceStr = $this->noceStr($timeStamp);
        $pay     = ["appId" => $appId, "timeStamp" => $timeStamp, "nonceStr" => $noceStr, "package" => "prepay_id=".$prepayid, "signType" => "MD5",];
        // 生成签名
        $pay["sign"] = $this->sign($pay, $wx_mini_key);

        return $pay;
    }

    // 获取随机字符串
    protected function noceStr($timeStamp)
    {
        return md5(rand(100, 1000).$timeStamp);
    }

    //  sign拼装获取
    protected function sign($param, $key)
    {
        $sign = "";
        ksort($param);
        foreach($param as $k => $v){
            $sign .= $k."=".$v."&";
        }

        $sign .= "key=".$key;
        $sign = strtoupper(md5($sign));

        return $sign;
    }

    //私钥，这里需要手动防止好私钥证书，并且需要修改下存放的位置
    protected function getMchKey()
    {
        //path->私钥文件存放路径
        return openssl_get_privatekey(file_get_contents('path'));
    }

    // 支付日志
    protected function logCurl($param)
    {
        $ds   = DIRECTORY_SEPARATOR;
        $path = app()->basePath().$ds.'Runtime'.$ds.'pay'.$ds;
        $dir  = new Dir();
        $dir->makeDir($path);

        $file = $path.'pay_'.date('Y-m-d').'.log';
        file_put_contents($file, date('y-m-d H:i:s').' 提交参数信息ch:'.json_encode($param)."\r\n\r\n", FILE_APPEND);
    }

    /* 获取订单号 */
    protected function getOrderNo($uid)
    {
        $orderNo = $uid.'_'.date('YmdHis').rand(100, 999);

        return $orderNo;
    }
}


